import re
from typing import Optional, Union, Any, Dict, List
from email_validator import validate_email, EmailNotValidError


def is_valid_email(email: str) -> bool:
    """验证邮箱格式"""
    try:
        validate_email(email)
        return True
    except EmailNotValidError:
        return False


def is_valid_phone(phone: str, country_code: str = "CN") -> bool:
    """验证手机号格式"""
    if country_code == "CN":
        # 中国手机号正则
        pattern = r'^1[3-9]\d{9}$'
        return bool(re.match(pattern, phone))
    
    # 其他国家可以扩展
    return False


def is_valid_username(username: str) -> bool:
    """验证用户名格式（字母、数字、下划线，3-20位）"""
    pattern = r'^[a-zA-Z0-9_]{3,20}$'
    return bool(re.match(pattern, username))


def is_valid_password(password: str, min_length: int = 6, max_length: int = 20) -> bool:
    """验证密码强度"""
    if not min_length <= len(password) <= max_length:
        return False
    
    # 至少包含一个字母和一个数字
    has_letter = bool(re.search(r'[a-zA-Z]', password))
    has_digit = bool(re.search(r'\d', password))
    
    return has_letter and has_digit


def is_valid_device_code(device_code: str) -> bool:
    """验证设备编码格式"""
    # 设备编码格式：字母+数字+下划线，3-30位
    pattern = r'^[A-Z0-9_]{3,30}$'
    return bool(re.match(pattern, device_code.upper()))


def is_valid_order_number(order_number: str) -> bool:
    """验证工单号格式"""
    # 工单号格式：WO + 年月日 + 6位数字
    pattern = r'^WO\d{8}\d{6}$'
    return bool(re.match(pattern, order_number))


def is_valid_coordinates(latitude: float, longitude: float) -> bool:
    """验证经纬度坐标"""
    return -90 <= latitude <= 90 and -180 <= longitude <= 180


def is_valid_percentage(value: Union[int, float]) -> bool:
    """验证百分比值"""
    return 0 <= value <= 100


def is_valid_url(url: str) -> bool:
    """验证URL格式"""
    pattern = r'^https?:\/\/(?:[-\w.])+(?:\:[0-9]+)?(?:\/(?:[\w\/_.])*)?(?:\?(?:[\w&=%.])*)?(?:\#(?:[\w.])*)?$'
    return bool(re.match(pattern, url))


def is_valid_ip_address(ip: str) -> bool:
    """验证IP地址格式"""
    pattern = r'^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$'
    return bool(re.match(pattern, ip))


def validate_required_fields(data: Dict[str, Any], required_fields: List[str]) -> List[str]:
    """验证必填字段"""
    missing_fields = []
    
    for field in required_fields:
        if field not in data or data[field] is None or data[field] == "":
            missing_fields.append(field)
    
    return missing_fields


def validate_field_length(value: str, field_name: str, min_length: int = 0, max_length: int = None) -> Optional[str]:
    """验证字段长度"""
    if len(value) < min_length:
        return f"{field_name}长度不能少于{min_length}个字符"
    
    if max_length and len(value) > max_length:
        return f"{field_name}长度不能超过{max_length}个字符"
    
    return None


def validate_field_range(value: Union[int, float], field_name: str, min_value: Union[int, float] = None, max_value: Union[int, float] = None) -> Optional[str]:
    """验证数值范围"""
    if min_value is not None and value < min_value:
        return f"{field_name}不能小于{min_value}"
    
    if max_value is not None and value > max_value:
        return f"{field_name}不能大于{max_value}"
    
    return None


def validate_field_in_choices(value: Any, field_name: str, choices: List[Any]) -> Optional[str]:
    """验证字段值是否在选择范围内"""
    if value not in choices:
        return f"{field_name}必须是以下值之一：{', '.join(map(str, choices))}"
    
    return None


def sanitize_string(value: str) -> str:
    """清理字符串，移除危险字符"""
    if not isinstance(value, str):
        return str(value)
    
    # 移除HTML标签
    value = re.sub(r'<[^>]*>', '', value)
    
    # 移除SQL注入风险字符
    dangerous_chars = ["'", '"', ';', '--', '/*', '*/', 'xp_', 'sp_']
    for char in dangerous_chars:
        value = value.replace(char, '')
    
    # 移除前后空白字符
    return value.strip()


def sanitize_filename(filename: str) -> str:
    """清理文件名，移除危险字符"""
    # 只保留字母、数字、点、下划线、横线
    clean_name = re.sub(r'[^a-zA-Z0-9._-]', '', filename)
    
    # 确保文件名不为空
    if not clean_name:
        clean_name = "untitled"
    
    return clean_name


def validate_file_extension(filename: str, allowed_extensions: List[str]) -> bool:
    """验证文件扩展名"""
    if '.' not in filename:
        return False
    
    extension = '.' + filename.rsplit('.', 1)[1].lower()
    return extension in allowed_extensions


def validate_file_size(file_size: int, max_size: int) -> bool:
    """验证文件大小"""
    return file_size <= max_size


class ValidationError(Exception):
    """验证错误异常"""
    
    def __init__(self, field: str, message: str, value: Any = None):
        self.field = field
        self.message = message
        self.value = value
        super().__init__(f"{field}: {message}")


class Validator:
    """验证器类"""
    
    def __init__(self):
        self.errors = []
    
    def add_error(self, field: str, message: str, value: Any = None):
        """添加验证错误"""
        self.errors.append({
            "field": field,
            "message": message,
            "value": value
        })
    
    def validate_required(self, data: Dict[str, Any], field: str) -> 'Validator':
        """验证必填字段"""
        if field not in data or data[field] is None or data[field] == "":
            self.add_error(field, f"{field}是必填字段")
        return self
    
    def validate_email(self, data: Dict[str, Any], field: str) -> 'Validator':
        """验证邮箱"""
        if field in data and data[field]:
            if not is_valid_email(data[field]):
                self.add_error(field, "邮箱格式不正确", data[field])
        return self
    
    def validate_phone(self, data: Dict[str, Any], field: str) -> 'Validator':
        """验证手机号"""
        if field in data and data[field]:
            if not is_valid_phone(data[field]):
                self.add_error(field, "手机号格式不正确", data[field])
        return self
    
    def validate_length(self, data: Dict[str, Any], field: str, min_length: int = 0, max_length: int = None) -> 'Validator':
        """验证长度"""
        if field in data and data[field]:
            error = validate_field_length(str(data[field]), field, min_length, max_length)
            if error:
                self.add_error(field, error, data[field])
        return self
    
    def validate_range(self, data: Dict[str, Any], field: str, min_value: Union[int, float] = None, max_value: Union[int, float] = None) -> 'Validator':
        """验证数值范围"""
        if field in data and data[field] is not None:
            error = validate_field_range(data[field], field, min_value, max_value)
            if error:
                self.add_error(field, error, data[field])
        return self
    
    def validate_choices(self, data: Dict[str, Any], field: str, choices: List[Any]) -> 'Validator':
        """验证选择"""
        if field in data and data[field] is not None:
            error = validate_field_in_choices(data[field], field, choices)
            if error:
                self.add_error(field, error, data[field])
        return self
    
    def is_valid(self) -> bool:
        """检查是否有效"""
        return len(self.errors) == 0
    
    def get_errors(self) -> List[Dict[str, Any]]:
        """获取错误列表"""
        return self.errors
    
    def raise_if_invalid(self):
        """如果无效则抛出异常"""
        if not self.is_valid():
            raise ValidationError("validation", f"验证失败，共{len(self.errors)}个错误", self.errors)